home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 October: Technology Seed / ADC Seed CD - October 1999.toast / FireWire / FireWire_2.0_SDK / Source / SBP2 / FWSBP2Driver / FWSBP2Driver.c next >
Encoding:
C/C++ Source or Header  |  1999-04-12  |  39.6 KB  |  1,359 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        FWSBP2Driver.c
  3.  
  4.     Contains:    Sample SBP-2 driver
  5.  
  6.     Version:    1.0
  7.  
  8.     Copyright:    © 1998-1999 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     File Ownership:
  11.  
  12.         DRI:                Eric Anderson
  13.  
  14.         Other Contact:        
  15.  
  16.         Technology:            FireWire
  17.  
  18.     Writers:
  19.  
  20.         (EA)    Eric Anderson (ewa)
  21.         (DCB)    Clinton Bauder
  22.  
  23.     Change History (most recent first):
  24.  
  25.       <FW11>     1/10/99    EA        Added support for testing cable power management API.
  26.       <FW10>      1/3/99    EA        Changed read block function to append dummy ORB, then a chain of
  27.                                     ORBS, to test non-immediate append.
  28.        <FW9>      1/3/99    EA        Added (and commented out) a simple test of
  29.                                     FWGetSBP2NormalCommandObjectIDFromORB_POINTER.
  30.        <FW8>      1/1/99    EA        Added test of FWGetFWReferenceIDFromUniqueID when we query
  31.                                     logins.  Also allocate memory for our ORB command object.
  32.        <FW7>    12/31/98    EA        Removed DebugStr that reported LUN status.  Note that Query
  33.                                     Logins doesn't report a timeout correctly yet.
  34.        <FW6>    12/31/98    EA        Added support for Query Logins.
  35.        <FW5>    12/31/98    EA        Added support for sending a TARGET RESET management ORB.  Also
  36.                                     set max payload size to 512 (now that FSL enforces it).
  37.        <FW4>    11/18/98    EA        Changed to report LUN.
  38.        <FW3>    10/28/98    DCB        Using new defs for matching SBP drivers. This allows us to be
  39.                                     much more specific in our decision as to which driver belongs to
  40.                                     which device.
  41.        <FW2>     9/20/98    EA        Filled in header comments.
  42.        <FW1>     9/20/98    EA        first checked in
  43. */
  44.  
  45.  
  46. #include <Types.h>
  47. #include <Errors.h>
  48. #include <Devices.h>
  49. #include <DriverServices.h>
  50. #include <FireWire.h>
  51. #include <FireWireSBP2.h>
  52. #include <SampleSBP2.h>
  53. #include <FWSBP2Driver.h>
  54. /*zzz*/
  55. #include <TextUtils.h>
  56. #include <stdio.h>
  57. char    debugStr[256];
  58. /*zzz*/
  59.  
  60.  
  61. ////////////////////////////////////////////////////////////////////////////////
  62. //
  63. // Internal procedure prototypes.
  64. //
  65.  
  66. static OSStatus    FWSBP2Initialize (
  67.     RegEntryIDPtr                pRegEntryID);
  68.  
  69. static OSStatus    FWSBP2Terminate (void);
  70.  
  71. static OSStatus    SBPDriverInterface (
  72.     SBPInterfaceParamsPtr        pSBPInterfaceParams);
  73.  
  74. static OSStatus    SBP2Login (
  75.     SBPLoginParamsPtr            pSBPLoginParams);
  76.  
  77. static OSStatus    SBP2Logout (
  78.     SBPLogoutParamsPtr            pSBPLogoutParams);
  79.  
  80. static OSStatus    SBP2Status (
  81.     SBPStatusParamsPtr            pSBPStatusParams);
  82.  
  83. static OSStatus SBP2DoQueryLogins(
  84.     SBPQueryLoginsParamsPtr    pSBPQueryLoginsParams);
  85.  
  86. static OSStatus SBP2DoStatusInquiry(
  87.     SBPStatusInquiryParamsPtr    pSBPStatusInquiryParams);
  88.  
  89. static OSStatus SBP2DoModeSense(
  90.     SBPModeSenseParamsPtr        pSBPModeSenseParams);
  91.  
  92. static OSStatus SBP2DoReadBlock(
  93.     SBPReadBlockParamsPtr        pSBPReadBlockParams);
  94.  
  95. static OSStatus SBP2DoTargetReset(
  96.     SBPTargetResetParamsPtr        pSBPTargetResetParams);
  97.  
  98. static OSStatus SBP2DoPowerTest(
  99.     SBPPowerTestParamsPtr        pSBPPowerTestParams);
  100.  
  101. static OSStatus SBPLoginNotify(
  102.     FWClientSBP2NotifyParamsPtr    pFWClientSBP2NotifyParams,
  103.     UInt32                        *pCommandAcceptance);
  104.  
  105. static OSStatus SBPStatusNotify(
  106.     FWClientSBP2NotifyParamsPtr    pFWClientSBP2NotifyParams,
  107.     UInt32                        *pCommandAcceptance);
  108.  
  109. static OSStatus SBPUnsolicitedStatusNotify(
  110.     FWClientSBP2NotifyParamsPtr    pFWClientSBP2NotifyParams,
  111.     UInt32                        *pCommandAcceptance);
  112.  
  113. #if 0
  114. static void    SBP2ClientCommandCompletionProc (
  115.     FWCommandObjectID            fwCommandObjectID,
  116.     OSStatus                    commandStatus,
  117.     UInt32                        completionProcData);
  118. #endif
  119.  
  120.  
  121. ////////////////////////////////////////////////////////////////////////////////
  122. //
  123. // The driver descriptor.
  124. //
  125.  
  126. DriverDescription                 TheDriverDescription =
  127. {
  128.     kTheDescriptionSignature,
  129.     kInitialDriverDescriptor,
  130.     {
  131.         "\psbp509e,10483",        //zzz what a certain hard drive returned
  132.         1, 0, finalStage, 1,
  133.     },
  134.     {
  135.         kDriverIsUnderExpertControl,
  136.         "\pFWSBP2Driver",
  137.     },
  138.  
  139.     1,
  140.     kServiceCategoryNdrvDriver,
  141.     kNdrvTypeIsSampleSBP2,
  142.     1,0,0,0
  143. };
  144.  
  145. ////////////////////////////////////////////////////////////////////////////////
  146. //
  147. // A quick note on how this works:
  148. //
  149. // The SBP2Expert creates sub-nodes for each LUN 
  150. // ...:firewire:fw609e,10483
  151. // ...:firewire:fw609e,10483:sbpXXXXXX,YYYYYY
  152. // ...:firewire:fw609e,10483:sbpPPPPPP,QQQQQQ
  153. //
  154. // XXXXXX is the command_set_spec_ID of lun 0.  YYYYYY is the command_set of lun 0.
  155. // PPPPPP is the command_set_spec_ID if lun 1.  QQQQQQ is the command_set of lun 1.  etc.
  156. //
  157. // The name of the driver then should match the sub-node created by the expert. To further
  158. // narrow down the match the SBP2Expert creates a table with the VendorID, SoftwareRev,
  159. // FirmwareRev, LUN and device_type values from the CSR ROM. This table is contained  in
  160. // a property called "TheDFMTable". The format for this table is in FireWireSBP2.h.
  161. // A similar table is exported by the driver and is called TheDFMDescriptor. It is exactly
  162. // twice the size of TheDFMTable as it contains a range for each value exported by the expert.
  163. // Drivers which match the greatest number of values in the table are selected to match the
  164. // device. Fields with a negative range are marked as "don't care". 
  165. //
  166. // Note that "don't care" is different from matching everything. Matching everything means
  167. // the score for the driver will be incremented for that field while don't care means that
  168. // it won't be. Thus a driver with 3 matches and 1 don't care scores lower than a driver
  169. // with 4 matches - even if the matches are the 0 through 0xFFFFFFFF type.
  170. //
  171. // Drivers with identical scores will be ranked by version as with other native drivers.
  172.  
  173. SBPMatchData                        TheDFMDescriptor = 
  174. {
  175.     0xFFFFFFFF, 0x00000000,            // VendorID, match all             (only low 24 bits valid)
  176.     0xFFFFFFFF, 0x00000000,            // SoftwareRev, match all        (only low 24 bits valid)
  177.     0xFFFFFFFF, 0x00000000,            // FirmwareRev, match all         (indicated by negative range)
  178.     0xFFFFFFFF, 0x00000000,            // LUN, match all                 (only low 16 bits valid)
  179.     0xFFFFFFFF, 0x00000000            // device_type, match all         (only low 5 bits valid)
  180. };
  181.  
  182. ////////////////////////////////////////////////////////////////////////////////
  183. //
  184. // Global driver data.
  185. //
  186.  
  187. FWSBP2DriverDataPtr                gpFWSBP2DriverData = nil;
  188.  
  189.  
  190. ////////////////////////////////////////////////////////////////////////////////
  191. //
  192. // DoDriverIO
  193. //
  194. //   Main entry point.
  195. //
  196.  
  197. OSErr    DoDriverIO(
  198.     AddressSpaceID                addressSpaceID,
  199.     IOCommandID                    ioCommandID,
  200.     IOCommandContents            ioCommandContents,
  201.     IOCommandCode                ioCommandCode,
  202.     IOCommandKind                ioCommandKind)
  203. {
  204.     CntrlParamPtr                pCntrlParam;
  205.     OSErr                        err = noErr;
  206.  
  207.     switch (ioCommandCode)
  208.     {
  209.         case kInitializeCommand :
  210.             err = FWSBP2Initialize (&ioCommandContents.initialInfo->deviceEntry);
  211.             break;
  212.  
  213.         case kFinalizeCommand :
  214.             err = FWSBP2Terminate ();
  215.  
  216.         case kOpenCommand :
  217.             break;
  218.  
  219.         case kCloseCommand :
  220.             break;                    //zzz should probably do a logout
  221.  
  222.         case kControlCommand :
  223.             pCntrlParam = (CntrlParamPtr) ioCommandContents.pb;
  224.             if (pCntrlParam->csCode == cscSBPCommand)
  225.             {
  226.                 err = SBPDriverInterface
  227.                         (*((SBPInterfaceParamsPtr *) &(pCntrlParam->csParam[0])));
  228.             }
  229.             else
  230.             {
  231.                 err = controlErr;
  232.             }
  233.             break;
  234.  
  235.         case kStatusCommand :
  236.             err = statusErr;
  237.             break;
  238.  
  239.         default :
  240.             err = paramErr;
  241.     }
  242.  
  243.     // We're complete.
  244.     if (ioCommandKind == kImmediateIOCommandKind)
  245.         return (err);
  246.     else
  247.         return (IOCommandIsComplete (ioCommandID, err));
  248.  
  249.     return (err);
  250. }
  251.  
  252.  
  253. ////////////////////////////////////////////////////////////////////////////////
  254. //
  255. // SBPDriverInterface
  256. //
  257. //   Main driver interface.
  258. //
  259.  
  260. static OSStatus    SBPDriverInterface(
  261.     SBPInterfaceParamsPtr        pSBPInterfaceParams)
  262. {
  263.     UInt32                        interfaceSelector;
  264.     OSStatus                    status = noErr;
  265.  
  266.     // Get some params.
  267.     interfaceSelector = pSBPInterfaceParams->interfaceSelector;
  268.  
  269.     // Note - most real SBP-2 drivers would not have these dispatches.
  270.     // A disk driver would have open, close, read, write - etc.  The
  271.     // driver would decide when to perform a login, mode sense, etc.,
  272.     // without being told to do these specific things.
  273.     
  274.     // Main dispatch.
  275.     switch (interfaceSelector)
  276.     {
  277.         case kSampleSBPLogin :
  278.             status = SBP2Login ((SBPLoginParamsPtr) pSBPInterfaceParams);
  279.             break;
  280.  
  281.         case kSampleSBPLogout :
  282.             status = SBP2Logout ((SBPLogoutParamsPtr) pSBPInterfaceParams);
  283.             break;
  284.  
  285.         case kSampleSBPStatus :
  286.             status = SBP2Status ((SBPStatusParamsPtr) pSBPInterfaceParams);
  287.             break;
  288.  
  289.         case kSampleSBPQueryLogins :
  290.             status = SBP2DoQueryLogins ((SBPQueryLoginsParamsPtr) pSBPInterfaceParams);
  291.             break;
  292.  
  293.         case kSampleSBPStatusInquiry :
  294.             status = SBP2DoStatusInquiry ((SBPStatusInquiryParamsPtr) pSBPInterfaceParams);
  295.             break;
  296.  
  297.         case kSampleSBPModeSense :
  298.             status = SBP2DoModeSense ((SBPModeSenseParamsPtr) pSBPInterfaceParams);
  299.             break;
  300.  
  301.         case kSampleSBPReadBlock :
  302.             status = SBP2DoReadBlock ((SBPReadBlockParamsPtr) pSBPInterfaceParams);
  303.             break;
  304.  
  305.         case kSampleSBPTargetReset :
  306.             status = SBP2DoTargetReset ((SBPTargetResetParamsPtr) pSBPInterfaceParams);
  307.             break;
  308.  
  309.         case kSampleSBPPowerTest :
  310.             status = SBP2DoPowerTest ((SBPPowerTestParamsPtr) pSBPInterfaceParams);
  311.             break;
  312.  
  313.         default :
  314.             status = paramErr;
  315.             break;
  316.     }
  317.  
  318.     return (status);
  319. }
  320.  
  321.  
  322. ////////////////////////////////////////////////////////////////////////////////
  323. //
  324. // FWSBP2Initialize
  325. //
  326. //   This routine initializes the FireWire SBP2 sample driver.  It
  327. // allocates a private data record and registers with the FireWire family.
  328. // It also prepares some command objects for use later on.
  329. //
  330.  
  331. static OSStatus SBPLoginNotify(
  332.     FWClientSBP2NotifyParamsPtr    pFWClientSBP2NotifyParams,
  333.     UInt32                        *pCommandAcceptance);
  334.  
  335. static OSStatus    FWSBP2Initialize(
  336.     RegEntryIDPtr                pRegEntryID)
  337. {
  338.     FWSBP2DriverDataPtr            pFWSBP2DriverData = nil;
  339.     FWDriverID                    fwDriverID;
  340.     OSStatus                    status = noErr;
  341.  
  342.     // Allocate our driver data.
  343.     pFWSBP2DriverData =
  344.         (FWSBP2DriverDataPtr) PoolAllocateResident (sizeof (FWSBP2DriverData), true);
  345.     if (pFWSBP2DriverData == nil)
  346.     {
  347.         status = memFullErr;
  348.     }
  349.  
  350.     // Register with the FireWire family.
  351.     if (status == noErr)
  352.     {
  353.         status = FWRegisterDriver (pRegEntryID,
  354.                                    &fwDriverID,
  355.                                    &(pFWSBP2DriverData->csrUnitID),
  356.                                    (UInt32) pFWSBP2DriverData);
  357.  
  358.         if (status == noErr)
  359.             pFWSBP2DriverData->fwDriverID = fwDriverID;
  360.     }
  361.  
  362.     // Get reference to local node.
  363.     if (status == noErr)
  364.     {
  365.         status = FWGetLocalFWReferenceIDFromFWReferenceID
  366.                     (pFWSBP2DriverData->fwDriverID,
  367.                      &(pFWSBP2DriverData->localFWReferenceID));
  368.     }
  369.  
  370.     // Set the maximum packet payload size.
  371.     if (status == noErr)
  372.     {
  373.         status = FWSetMaxPayloadSize ((FWReferenceID) pFWSBP2DriverData->fwDriverID, 512);
  374.     }
  375.  
  376.     // Allocate login command object.
  377.     if (status == noErr)
  378.     {
  379.         status = FWAllocateSBP2LoginCommandObject ((FWReferenceID) pFWSBP2DriverData->fwDriverID,
  380.                                                    &pFWSBP2DriverData->loginCommandID);
  381.     }
  382.     
  383.     if (status != noErr) pFWSBP2DriverData->loginCommandID = 0;
  384.  
  385.     // Prepare login command object.
  386.     if (status == noErr)
  387.         status = FWSetFWCommandFlags (pFWSBP2DriverData->loginCommandID, kFWCommandSyncFlag);
  388.  
  389.     if (status == noErr)
  390.     {
  391.         status = FWSetSBP2LoginCommandFlags (pFWSBP2DriverData->loginCommandID,
  392.                                              kSBP2NotifyOnLoginComplete |
  393.                                              kSBP2NotifyOnLoginFailed |
  394.                                              kSBP2NotifyOnReconnecting |
  395.                                              kSBP2NotifyOnReconnectComplete |
  396.                                              kSBP2NotifyOnReconnectFailed);
  397.     }
  398.     
  399.     if (status == noErr)
  400.     {
  401.         status = FWSetSBP2LoginCommandMaxPayloadSize (pFWSBP2DriverData->loginCommandID, 512);
  402.     }
  403.  
  404.     if (status == noErr)
  405.     {
  406.         status = FWSetSBP2LoginCommandLoginNotifyProc (pFWSBP2DriverData->loginCommandID,
  407.                                                        SBPLoginNotify,
  408.                                                        (UInt32) pFWSBP2DriverData);
  409.     }
  410.  
  411.     if (status == noErr)
  412.     {
  413.         status = FWSetSBP2LoginCommandStatusNotifyProc (pFWSBP2DriverData->loginCommandID,
  414.                                                         SBPStatusNotify,
  415.                                                         (UInt32) pFWSBP2DriverData);
  416.     }
  417.  
  418.     if (status == noErr)
  419.     {
  420.         status = FWSetSBP2LoginCommandUnsolicitedStatusNotifyProc (pFWSBP2DriverData->loginCommandID,
  421.                                                                    SBPUnsolicitedStatusNotify,
  422.                                                                    (UInt32) pFWSBP2DriverData);
  423.     }
  424.  
  425.     // Allocate a dummy ORB command object.
  426.     if (status == noErr)
  427.     {
  428.         status = FWAllocateSBP2NormalCommandObject (pFWSBP2DriverData->loginCommandID,
  429.                                                     &pFWSBP2DriverData->dummyOrbID);
  430.     }
  431.     
  432.     if (status != noErr) pFWSBP2DriverData->dummyOrbID = 0;
  433.     
  434.     if (status == noErr)
  435.         status = FWAllocateFWCommandObjectMemory (pFWSBP2DriverData->dummyOrbID, 3 * 4096);
  436.  
  437.     // Allocate an ORB command object.
  438.     if (status == noErr)
  439.     {
  440.         status = FWAllocateSBP2NormalCommandObject (pFWSBP2DriverData->loginCommandID,
  441.                                                     &pFWSBP2DriverData->firstOrbID);
  442.     }
  443.     
  444.     if (status != noErr) pFWSBP2DriverData->firstOrbID = 0;
  445.     
  446.     if (status == noErr)
  447.         status = FWAllocateFWCommandObjectMemory (pFWSBP2DriverData->firstOrbID, 3 * 4096);
  448.  
  449.     // Allocate another ORB command object.
  450.     if (status == noErr)
  451.     {
  452.         status = FWAllocateSBP2NormalCommandObject (pFWSBP2DriverData->loginCommandID,
  453.                                                     &pFWSBP2DriverData->orbID);
  454.     }
  455.     
  456.     if (status != noErr) pFWSBP2DriverData->orbID = 0;
  457.     
  458.     if (status == noErr)
  459.         status = FWAllocateFWCommandObjectMemory (pFWSBP2DriverData->orbID, 3 * 4096);
  460.  
  461.     // Allocate a management ORB command object.
  462.     if (status == noErr)
  463.     {
  464.         status = FWAllocateSBP2ManagementCommandObject ((FWReferenceID) pFWSBP2DriverData->fwDriverID,
  465.                                                         &pFWSBP2DriverData->managementORBID);
  466.     }
  467.     
  468.     if (status != noErr) pFWSBP2DriverData->managementORBID = 0;
  469.     
  470.     // Allocate an asynch command object for writing to the AGENT_RESET register.
  471.     if (status == noErr)
  472.     {
  473.         status = FWAllocateAsynchCommandObject (&pFWSBP2DriverData->fwAGENT_RESET_ID);
  474.     }
  475.  
  476.     if (status == noErr)
  477.     {
  478.         status = FWSetFWCommandParams (pFWSBP2DriverData->fwAGENT_RESET_ID,
  479.                                        pFWSBP2DriverData->fwDriverID,
  480.                                        kFWCommandSyncFlag,
  481.                                        nil,
  482.                                        0);
  483.     }
  484.  
  485.     // The AGENT_RESET command object will be filled in some more after we get the
  486.     // login response and we learn the address of the fetch agent.
  487.     
  488.     // Allocate an asynch command object for writing to the DOORBELL register.
  489.     if (status == noErr)
  490.     {
  491.         status = FWAllocateAsynchCommandObject (&pFWSBP2DriverData->fwDOORBELL_ID);
  492.     }
  493.  
  494.     if (status == noErr)
  495.     {
  496.         status = FWSetFWCommandParams (pFWSBP2DriverData->fwDOORBELL_ID,
  497.                                        pFWSBP2DriverData->fwDriverID,
  498.                                        kFWCommandSyncFlag,
  499.                                        nil,
  500.                                        0);
  501.     }
  502.  
  503.     // The DOORBELL command object will be filled in some more after we get the
  504.     // login response and we learn the address of the fetch agent.
  505.     
  506.     // Allocate an asynch command object for reading the ORB_POINTER register.
  507.     if (status == noErr)
  508.     {
  509.         status = FWAllocateAsynchCommandObject (&pFWSBP2DriverData->readORB_POINTER_ID);
  510.     }
  511.  
  512.     if (status == noErr)
  513.     {
  514.         status = FWSetFWCommandParams (pFWSBP2DriverData->readORB_POINTER_ID,
  515.                                        pFWSBP2DriverData->fwDriverID,
  516.                                        kFWCommandSyncFlag,
  517.                                        nil,
  518.                                        0);
  519.     }
  520.  
  521.     // Allocate a Cable Power Management command object
  522.     if (status == noErr)
  523.     {
  524.         status = FWAllocatePowerCommandObject (&pFWSBP2DriverData->powerChangeID);
  525.     }
  526.     
  527.     if (status == noErr)
  528.     {
  529.         status = FWSetFWCommandParams (pFWSBP2DriverData->powerChangeID,
  530.                                        pFWSBP2DriverData->fwDriverID,
  531.                                        kFWCommandSyncFlag,
  532.                                        nil,
  533.                                        0);
  534.     }
  535.  
  536.     if (status == noErr)
  537.     {
  538.         pFWSBP2DriverData->notificationMessage = PoolAllocateResident (1024, true);
  539.         if (!pFWSBP2DriverData->notificationMessage)
  540.             status = memFullErr;
  541.     }
  542.         
  543.     // Make a note of our LUN
  544.     if (status == noErr)
  545.     {
  546.         status = FWGetSBP2LUNFromFWReferenceID (pFWSBP2DriverData->fwDriverID,
  547.                                                 &pFWSBP2DriverData->lun);
  548.  
  549. //sprintf (debugStr, "Driver get status %ld lun %ld",
  550. //         (long) status, (long) pFWSBP2DriverData->lun);
  551. //DebugStr ((ConstStr255Param) c2pstr (debugStr));
  552.  
  553.     }
  554.  
  555.     // Save our driver data or clean up on error.
  556.     if (status == noErr)
  557.     {
  558.         gpFWSBP2DriverData = pFWSBP2DriverData;
  559.     }
  560.     else
  561.     {//zzz should use terminate
  562.         if (pFWSBP2DriverData != nil)
  563.             PoolDeallocate ((Ptr) pFWSBP2DriverData);
  564.     }
  565.  
  566.     return status;
  567. }
  568.  
  569.  
  570. ////////////////////////////////////////////////////////////////////////////////
  571. //
  572. // FWSBP2Terminate
  573. //
  574. //   This routine terminates the FireWire SBP2 sample driver.  It
  575. // deallocates a private data record and unregisters with the FireWire family.
  576. //
  577. // Note, with the sample family and app, this routine is never called.
  578. // Even if you unplug the device, nobody terminates the driver.
  579. //
  580.  
  581. static OSStatus    FWSBP2Terminate(void)
  582. {
  583.     OSStatus                    status = noErr;
  584.  
  585.     if (gpFWSBP2DriverData != nil)
  586.     {
  587.         // Unregister with FireWire family.
  588.         if (gpFWSBP2DriverData->fwDriverID != kInvalidFWDriverID)
  589.             FWUnregisterDriver (gpFWSBP2DriverData->fwDriverID);
  590.  
  591.         //zzz We should check that ORB is not active before we deallocate it.
  592.         // We could issue a target reset to guarantee this.
  593.         
  594.         if (gpFWSBP2DriverData->orbID)
  595.             FWDeallocateFWCommandObject (gpFWSBP2DriverData->orbID);
  596.  
  597.         if (gpFWSBP2DriverData->login)
  598.             FWSBP2Logout (gpFWSBP2DriverData->loginCommandID);
  599.         
  600.         if (gpFWSBP2DriverData->loginCommandID)
  601.             FWDeallocateFWCommandObject (gpFWSBP2DriverData->loginCommandID);
  602.  
  603.         // Deallocate our driver data.
  604.         PoolDeallocate ((Ptr) gpFWSBP2DriverData);
  605.         gpFWSBP2DriverData = nil;
  606.     }
  607.  
  608.     return status;
  609. }
  610.  
  611.  
  612. ////////////////////////////////////////////////////////////////////////////////
  613. //
  614. // SBP2Login
  615. //
  616. //   This routine performs a login.
  617. //
  618.  
  619. static OSStatus    SBP2Login(
  620.     SBPLoginParamsPtr            pSBPLoginParams)
  621. {
  622.     OSStatus                    status = noErr;
  623.  
  624.     gpFWSBP2DriverData->reconnectFailed = false;
  625.     gpFWSBP2DriverData->notificationEvent = 0;
  626.     gpFWSBP2DriverData->notificationCounter++;
  627.     
  628.     status = FWSBP2Login (gpFWSBP2DriverData->loginCommandID);
  629.     pSBPLoginParams->status = status;
  630.         
  631.     return noErr;
  632. }
  633.  
  634.  
  635. ////////////////////////////////////////////////////////////////////////////////
  636. //
  637. // SBP2Logout
  638. //
  639. //   This routine performs a logout.
  640. //
  641.  
  642. static OSStatus    SBP2Logout(
  643.     SBPLogoutParamsPtr            pSBPLogoutParams)
  644. {
  645.     OSStatus                    status = noErr;
  646.  
  647.     status = FWSBP2Logout (gpFWSBP2DriverData->loginCommandID);
  648.     pSBPLogoutParams->status = status;
  649.     
  650.     if (status == noErr) gpFWSBP2DriverData->login = false;
  651.     gpFWSBP2DriverData->notificationEvent = 0;
  652.     gpFWSBP2DriverData->notificationCounter++;
  653.  
  654.     return noErr;
  655. }
  656.  
  657.  
  658. ////////////////////////////////////////////////////////////////////////////////
  659. //
  660. // SBP2Status
  661. //
  662. //   This routine returns various status.
  663. //
  664.  
  665. static OSStatus    SBP2Status(
  666.     SBPStatusParamsPtr            pSBPStatusParams)
  667. {
  668.     OSStatus                    status = noErr;
  669.  
  670.     pSBPStatusParams->login = gpFWSBP2DriverData->login;
  671.     pSBPStatusParams->reconnecting = gpFWSBP2DriverData->reconnecting;
  672.     pSBPStatusParams->reconnectFailed = gpFWSBP2DriverData->reconnectFailed;
  673.     
  674.     pSBPStatusParams->notificationCounter = gpFWSBP2DriverData->notificationCounter;
  675.     pSBPStatusParams->notificationEvent = gpFWSBP2DriverData->notificationEvent;
  676.     pSBPStatusParams->notificationLength = gpFWSBP2DriverData->notificationLength;
  677.     
  678.     //zzz Driver should not share it's pointer with application.  Should copy buffer instead.
  679.     pSBPStatusParams->notificationMessage = gpFWSBP2DriverData->notificationMessage;
  680.     
  681.     pSBPStatusParams->lun = gpFWSBP2DriverData->lun;
  682.     
  683.     return noErr;
  684. }
  685.  
  686.  
  687. ////////////////////////////////////////////////////////////////////////////////
  688. //
  689. // SBP2DoQueryLogins
  690. //
  691. //   This routine sends a Query Logins management ORB.
  692. // This routine makes only synchronous calls, so it must be called only at task
  693. // level.
  694. //
  695.  
  696. static OSStatus SBP2DoQueryLogins(
  697.     SBPQueryLoginsParamsPtr        pSBPQueryLoginsParams)
  698. {
  699.     FWCommandObjectID            orbID;
  700.     CSRNodeUniqueID                uniqueID;
  701.     OSStatus                    status;
  702.  
  703.     gpFWSBP2DriverData->notificationEvent = 0;
  704.     gpFWSBP2DriverData->notificationCounter++;
  705.     orbID = gpFWSBP2DriverData->managementORBID;
  706.     
  707.     if (status == noErr)
  708.         status = FWSetSBP2ManagementCommandFunction (orbID, kSBP2QueryLogins);
  709.     
  710.     if (status == noErr)
  711.         status = FWSetSBP2ManagementCommandResponseBuffer (orbID, (Ptr) pSBPQueryLoginsParams->response, 256);
  712.     
  713.     if (status == noErr)
  714.         status = FWSetFWCommandFlags (orbID, kFWCommandSyncFlag);
  715.     
  716.     if (status == noErr)
  717.         status = FWSBP2Manage (orbID);
  718.     
  719.     // The Manage command was synchronous.  When it returns, the command has been
  720.     // sent to the target and the target has executed the command.
  721.     
  722.     // Using the first EUI-64 returned (if any), test FWGetFWReferenceIDFromUniqueID
  723.     // to see if it returns the corresponsing fwReferenceID, or an error if the ID is
  724.     // invalid (and thus not found).
  725.     
  726.     if (status == noErr)
  727.     {
  728.         uniqueID.hi = pSBPQueryLoginsParams->response[2];
  729.         uniqueID.lo = pSBPQueryLoginsParams->response[3];
  730.         pSBPQueryLoginsParams->uniqueIDStatus =
  731.             FWGetFWReferenceIDFromUniqueID (gpFWSBP2DriverData->fwDriverID,
  732.                                             uniqueID,
  733.                                             &pSBPQueryLoginsParams->fwReferenceID);
  734.         
  735.         if (pSBPQueryLoginsParams->uniqueIDStatus == noErr)
  736.             status = FWGetUniqueID (pSBPQueryLoginsParams->fwReferenceID,
  737.                                     &pSBPQueryLoginsParams->uniqueID);
  738.     }
  739.     
  740.     pSBPQueryLoginsParams->status = status;
  741.     
  742.     return noErr;
  743. }
  744.  
  745.  
  746. ////////////////////////////////////////////////////////////////////////////////
  747. //
  748. // SBP2DoStatusInquiry
  749. //
  750. //   This routine performs a status inquiry.  With the Symbios SYMFW2500 kit,
  751. // a status inquiry will clear a check condition and allow the drive to be used.
  752. // This routine makes only synchronous calls, so it must be called only at task
  753. // level.
  754. //
  755.  
  756. static OSStatus SBP2DoStatusInquiry(
  757.     SBPStatusInquiryParamsPtr    pSBPStatusInquiryParams)
  758. {
  759.     FWCommandObjectID            orbID;
  760.     FWAddress                    buffers[1];
  761.     UInt32                        lengths[1];
  762.     char                        buffer[256];
  763.     UInt8                        command[12] = {0x03, 0, 0, 0, 0x12, 0, 0, 0, 0, 0, 0, 0};
  764.     OSStatus                    status;
  765.  
  766.     gpFWSBP2DriverData->notificationEvent = 0;
  767.     gpFWSBP2DriverData->notificationCounter++;
  768.     orbID = gpFWSBP2DriverData->orbID;
  769.     
  770.     // Prepare the ORB.
  771.     
  772.     buffers[0].addressHi = 0;
  773.     buffers[0].addressLo = (UInt32) buffer;
  774.     lengths[0] = 18;
  775.     status = FWSetSBP2NormalCommandBuffers (orbID, 1, buffers, lengths);
  776.  
  777.     if (status == noErr)
  778.         status = FWSetSBP2NormalCommandCommand (orbID, (Ptr) command, 12);
  779.     
  780.     if (status == noErr)
  781.         status = FWSetSBP2NormalCommandTimeout (orbID, durationMillisecond * 1000);
  782.     
  783.     if (status == noErr)
  784.         status = FWSetSBP2NormalCommandFlags (orbID,
  785.                                               kSBP2CommandTransferDataFromTarget |
  786.                                               kSBP2CommandImmediate |
  787.                                               kSBP2CommandCompleteNotify);
  788.     
  789.     if (status == noErr)
  790.         status = FWSetFWCommandFlags (orbID, kFWCommandSyncFlag);
  791.     
  792.     if (status == noErr)
  793.         status = FWAppendSBP2Command (orbID);
  794.     
  795.     // The Append command was synchronous.  When it returns, the command has been
  796.     // appended to the target.  But the target probably has not executed the command yet.
  797.     
  798.     if (status == noErr)
  799.     {
  800.         //zzz Just wait for target to execute command.  Should use notification instead.
  801.         DelayFor (durationMillisecond * 1000);
  802.         //should have response by now
  803.     }
  804.     
  805.     // After a Status Inquiry, the SYM13FW2500 will be in the Dead state, so we
  806.     // need to reset the Fetch Agent.
  807.     if (status == noErr)
  808.         status = FWWrite (gpFWSBP2DriverData->fwAGENT_RESET_ID);
  809.  
  810.     // "buffer" was allocated on the stack.  So it would be very bad to return
  811.     // now if the ORB was still active.
  812.     
  813.     return noErr;
  814. }
  815.  
  816.  
  817. ////////////////////////////////////////////////////////////////////////////////
  818. //
  819. // SBP2DoModeSense
  820. //
  821. //   This routine performs a mode sense.  With the Symbios SYMFW2500 kit,
  822. // a mode sense will return some data about the drive that is connected.
  823. // This routine makes only synchronous calls, so it must be called only at task
  824. // level.
  825. //
  826.  
  827. static OSStatus SBP2DoModeSense(
  828.     SBPModeSenseParamsPtr        pSBPModeSenseParams)
  829. {
  830.     FWCommandObjectID            orbID;
  831.     FWAddress                    buffers[1];
  832.     UInt32                        lengths[1];
  833.     char                        buffer[256];
  834.     UInt8                        command[12] = {0x5a, 0x08, 0x3e, 0, 0, 0, 0, 0, 0xff, 0, 0, 0};
  835.     OSStatus                    status;
  836.  
  837.     gpFWSBP2DriverData->notificationEvent = 0;
  838.     gpFWSBP2DriverData->notificationCounter++;
  839.     orbID = gpFWSBP2DriverData->orbID;
  840.     
  841.     // Prepare the ORB.
  842.     
  843.     buffers[0].addressHi = 0;
  844.     buffers[0].addressLo = (UInt32) buffer;
  845.     lengths[0] = 255;
  846.     status = FWSetSBP2NormalCommandBuffers (orbID, 1, buffers, lengths);
  847.  
  848.     if (status == noErr)
  849.         status = FWSetSBP2NormalCommandCommand (orbID, (Ptr) command, 12);
  850.     
  851.     if (status == noErr)
  852.         status = FWSetSBP2NormalCommandTimeout (orbID, durationMillisecond * 1000);
  853.     
  854.     if (status == noErr)
  855.         status = FWSetSBP2NormalCommandFlags (orbID,
  856.                                               kSBP2CommandTransferDataFromTarget |
  857.                                               kSBP2CommandImmediate);
  858.     
  859.     if (status == noErr)
  860.         status = FWSetFWCommandFlags (orbID, kFWCommandSyncFlag);
  861.     
  862.     if (status == noErr)
  863.         status = FWAppendSBP2Command (orbID);
  864.     
  865.     // The Append command was synchronous.  When it returns, the command has been
  866.     // appended to the target.  But the target probably has not executed the command yet.
  867.     
  868.     if (status == noErr)
  869.     {
  870.         //zzz Just wait for target to execute command.  Should use notification instead.
  871.         DelayFor (durationMillisecond * 1000);
  872.         //should have response by now
  873.     }
  874.  
  875.     // My SYM13FW2500 does not understand the page_table_present bit, so the
  876.     // mode sense does not work (in fact, it tries to write the result onto
  877.     // the page table!)
  878.  
  879.     // "buffer" was allocated on the stack.  So it would be very bad to return
  880.     // now if the ORB was still active.
  881.     
  882.     return noErr;
  883. }
  884.  
  885.  
  886. ////////////////////////////////////////////////////////////////////////////////
  887. //
  888. // SBP2DoReadBlock
  889. //
  890. //   This routine reads block zero, assuming the target is a simple hard drive.
  891. // This routine makes only synchronous calls, so it must be called only at task
  892. // level.
  893. //
  894.  
  895. static OSStatus SBP2DoReadBlock(
  896.     SBPReadBlockParamsPtr        pSBPReadBlockParams)
  897. {
  898.     FWCommandObjectID            orbID, dummyOrbID, firstOrbID;
  899.     FWAddress                    buffers[1];
  900.     UInt32                        lengths[1];
  901.     char                        buffer[4096];
  902.     UInt8                        command[12];
  903.     UInt32                        lba = 0;
  904.     UInt16                        xfer = 1;
  905.     UInt32                        transferIsWrite = 0;
  906.     OSStatus                    status;
  907.  
  908.     gpFWSBP2DriverData->notificationEvent = 0;
  909.     gpFWSBP2DriverData->notificationCounter++;
  910.     dummyOrbID = gpFWSBP2DriverData->dummyOrbID;
  911.     firstOrbID = gpFWSBP2DriverData->firstOrbID;
  912.     orbID = gpFWSBP2DriverData->orbID;
  913.     
  914.     // Prepare a dummy ORB.
  915.     status = FWSetSBP2NormalCommandBuffers (dummyOrbID, 0, 0, 0);
  916.  
  917.     if (status == noErr)
  918.         status = FWSetSBP2NormalCommandFlags (dummyOrbID, kSBP2CommandDummyORB | kSBP2CommandImmediate);
  919.  
  920.     if (status == noErr)
  921.         status = FWSetFWCommandFlags (dummyOrbID, kFWCommandSyncFlag);
  922.     
  923.     // We're actually going to read two blocks, to see if ORB chaining works.
  924.     
  925.     // Prepare first ORB.
  926.     // Page table total length must agree with ATAPI request length, or drive
  927.     // will get confused.
  928.     
  929.     buffers[0].addressHi = 0;
  930.     buffers[0].addressLo = (UInt32) buffer;
  931.     lengths[0] = 512;
  932.     if (status == noErr)
  933.         status = FWSetSBP2NormalCommandBuffers (firstOrbID, 1, buffers, lengths);
  934.  
  935.     // Form ATAPI command (SCSI-3, cribbed from MMC-2 spec)
  936.     command[0] = (transferIsWrite ? 0x2A : 0x28);    // Write or Read
  937.     command[1] = 0;                                    // Mostly reserved
  938.     command[2] = (lba >> 24) & 0xff;                // MSB of LBA
  939.     command[3] = (lba >> 16) & 0xff;
  940.     command[4] = (lba >> 8) & 0xff;
  941.     command[5] = lba & 0xff;                        // LSB of LBA
  942.     command[6] = 0;                                    // Reserved
  943.     command[7] = (xfer >> 8) & 0xff;                // MSB of block count
  944.     command[8] = xfer & 0xff;                        // LSB of block count
  945.     command[9] = 0;                                    // Control (reserved)
  946.     command[10] = 0;
  947.     command[11] = 0;
  948.  
  949.     if (status == noErr)
  950.         status = FWSetSBP2NormalCommandCommand (firstOrbID, (Ptr) command, 12);
  951.     
  952.     if (status == noErr)
  953.         status = FWSetSBP2NormalCommandTimeout (firstOrbID, durationMillisecond * 100);
  954.     
  955.     if (status == noErr)
  956.         status = FWSetSBP2NormalCommandFlags (firstOrbID,
  957.                                               (transferIsWrite ? 0 : kSBP2CommandTransferDataFromTarget) |
  958.                                               kSBP2CommandCompleteNotify);
  959.  
  960.     if (status == noErr)
  961.         status = FWSetFWCommandFlags (firstOrbID, kFWCommandSyncFlag);
  962.     
  963.     // Second of two transfer ORBs
  964.     // Everything was copied into the ORB so we can recycle the arguments immediately.
  965.     buffers[0].addressLo = 512 + (UInt32) buffer;
  966.     command[5] = (lba+1) & 0xff;                        // LSB of LBA
  967.     
  968.     if (status == noErr)
  969.         status = FWSetSBP2NormalCommandBuffers (orbID, 1, buffers, lengths);
  970.  
  971.     if (status == noErr)
  972.         status = FWSetSBP2NormalCommandCommand (orbID, (Ptr) command, 12);
  973.     
  974.     if (status == noErr)
  975.         status = FWSetSBP2NormalCommandTimeout (orbID, durationMillisecond * 100);
  976.     
  977.     if (status == noErr)
  978.         status = FWSetSBP2NormalCommandFlags (orbID,
  979.                                               (transferIsWrite ? 0 : kSBP2CommandTransferDataFromTarget) |
  980.                                               kSBP2CommandCompleteNotify);
  981.  
  982.     if (status == noErr)
  983.         status = FWSetFWCommandFlags (orbID, kFWCommandSyncFlag);
  984.     
  985.     //////////////////
  986.     // Time for action
  987.     
  988.     if (status == noErr)
  989.         status = FWAppendSBP2Command (dummyOrbID);
  990.     
  991.     // The Append command was synchronous.  When it returns, the command has been
  992.     // appended to the target.  But the target probably has not executed the command yet.
  993.     
  994.     if (status == noErr)
  995.     {
  996.         //zzz Just wait for target to execute command.  Should use notification instead.
  997.         DelayFor (durationMillisecond * 100);
  998.         //should have response by now
  999.     }
  1000.  
  1001.     // Put two real ORBs on the list...
  1002.     
  1003.     if (status == noErr)
  1004.         status = FWAppendSBP2Command (firstOrbID);
  1005.     
  1006.     if (status == noErr)
  1007.         status = FWAppendSBP2Command (orbID);
  1008.     
  1009.     // Now we need to ring the doorbell to make the target wake up.
  1010.     
  1011.     if (status == noErr)
  1012.         status = FWWrite (gpFWSBP2DriverData->fwDOORBELL_ID);
  1013.     
  1014.     if (status == noErr)
  1015.     {
  1016.         //zzz Just wait for target to execute command.  Should use notification instead.
  1017.         DelayFor (durationMillisecond * 100);
  1018.         //should have response by now
  1019.     }
  1020.  
  1021.     // My SYM13FW2500 does not understand the page_table_present bit, so this
  1022.     // command does not work.  Probably my unit has old firmware.
  1023.  
  1024.     // This command works on the Seagate FireWire hard drive.
  1025.     
  1026.     // "buffer" was allocated on the stack.  So it would be very bad to return
  1027.     // now if the ORB was still active.
  1028.  
  1029. #define ORB_POINTER_TEST 0
  1030.  
  1031. #if ORB_POINTER_TEST
  1032.     if (status == noErr)
  1033.     {
  1034.         FWCommandObjectID        returnID;
  1035.         FWAddress                ORB_POINTER;
  1036.  
  1037.         status = FWSetAsynchCommandParams
  1038.             (gpFWSBP2DriverData->readORB_POINTER_ID,
  1039.              0,                                                    // generation - ignored
  1040.              gpFWSBP2DriverData->fetchAgent.addressHi,            // addr from login response
  1041.              gpFWSBP2DriverData->fetchAgent.addressLo + 8,        // + 8 to get ORB_POINTER
  1042.              (Ptr) &ORB_POINTER,                                // put result here
  1043.              8,                                                    // block read
  1044.              0,                                                    // max payload - ignored
  1045.              8,                                                    // max retries
  1046.              0);                                                // no flags
  1047.         
  1048.         // We set the synchronous flag when we allocated the object, and we set the max payload
  1049.         // size to 512 already, so we're all set:
  1050.         
  1051.         if (status == noErr)
  1052.             status = FWRead (gpFWSBP2DriverData->readORB_POINTER_ID);
  1053.  
  1054.         // When I tried this, everything worked fine except the drive sent back 00000000.00000001
  1055.         // as its ORB pointer, which obviously is wrong.  Forcing the result like this works:
  1056.         //ORB_POINTER.addressHi = 8;
  1057.         //ORB_POINTER.addressLo = 0;
  1058.         // This particular drive is not honoring SBP-2 9.1.4 where it says that when reaching a
  1059.         // null pointer the fetch agent should go into SUSPENDED state and the ORB_POINTER
  1060.         // register should contain the address of the ORB containing the null pointer.  Oh well.
  1061.  
  1062.         sprintf (debugStr, "Read of ORB_POINTER status = %ld, result = %08lx.%08lx",
  1063.                  (long) status, (long) ORB_POINTER.addressHi, (long) ORB_POINTER.addressLo);
  1064.         DebugStr ((ConstStr255Param) c2pstr (debugStr));
  1065.         
  1066.         if (status == noErr)
  1067.             status = FWGetSBP2NormalCommandObjectIDFromORB_POINTER (gpFWSBP2DriverData->loginCommandID,
  1068.                                                                     ORB_POINTER,
  1069.                                                                     &returnID);
  1070.  
  1071.         sprintf (debugStr, "Get...POINTER status = %ld, result = %08lx, real ORB ID = %08lx",
  1072.                  (long) status, (long) returnID, (long) orbID);
  1073.         DebugStr ((ConstStr255Param) c2pstr (debugStr));        
  1074.     }
  1075. #endif
  1076.  
  1077.     return noErr;
  1078. }
  1079.  
  1080.  
  1081. ////////////////////////////////////////////////////////////////////////////////
  1082. //
  1083. // SBP2DoTargetReset
  1084. //
  1085. //   This routine sends a TARGET RESET management ORB.
  1086. // This routine makes only synchronous calls, so it must be called only at task
  1087. // level.
  1088. //
  1089.  
  1090. static OSStatus SBP2DoTargetReset(
  1091.     SBPTargetResetParamsPtr        pSBPTargetResetParams)
  1092. {
  1093.     FWCommandObjectID            orbID;
  1094.     OSStatus                    status;
  1095.  
  1096.     gpFWSBP2DriverData->notificationEvent = 0;
  1097.     gpFWSBP2DriverData->notificationCounter++;
  1098.     orbID = gpFWSBP2DriverData->managementORBID;
  1099.     
  1100.     if (status == noErr)
  1101.         status = FWSetSBP2ManagementCommandFunction (orbID, kSBP2TargetReset);
  1102.     
  1103.     if (status == noErr)
  1104.         status = FWSetSBP2ManagementCommandCommandID (orbID, gpFWSBP2DriverData->loginCommandID);
  1105.     
  1106.     if (status == noErr)
  1107.         status = FWSetFWCommandFlags (orbID, kFWCommandSyncFlag);
  1108.     
  1109.     if (status == noErr)
  1110.         status = FWSBP2Manage (orbID);
  1111.     
  1112.     // The Manage command was synchronous.  When it returns, the command has been
  1113.     // sent to the target and the target has executed the command.
  1114.         
  1115.     // SBP-2 says the fetch agent will be dead after a RESET_TARGET, so reset it too.
  1116.     
  1117.     if (status == noErr)
  1118.         status = FWWrite (gpFWSBP2DriverData->fwAGENT_RESET_ID);
  1119.         
  1120.     return noErr;
  1121. }
  1122.  
  1123.  
  1124. ////////////////////////////////////////////////////////////////////////////////
  1125. //
  1126. // DummyPowerNotify
  1127. //
  1128. //   This is what a notification proc would look like (except a real one
  1129. // would probably do something useful.
  1130. //
  1131.  
  1132. static OSStatus    DummyPowerNotify (
  1133.     FWClientPowerNotifyParamsPtr    pPowerNotifyParams,
  1134.     UInt32                            *pCommandAcceptance)
  1135. {
  1136.     // Do something useful here.
  1137.     
  1138.     
  1139.     *pCommandAcceptance = kFWClientCommandAcceptNoMore;
  1140.     return FWClientCommandIsComplete (pPowerNotifyParams->fwClientInterfaceParams.fwClientCommandID, 0);
  1141. }
  1142.  
  1143.  
  1144. ////////////////////////////////////////////////////////////////////////////////
  1145. //
  1146. // SBP2DoPowerTest
  1147. //
  1148. //   This routine tests FWChangePower.  This just tests that the calls work,
  1149. // it doesn't really do anything.  This should return noErr if run on a
  1150. // Yosemite, and no real drivers are really using power.
  1151. //
  1152. // This routine makes only synchronous calls, so it must be called only at task
  1153. // level.
  1154. //
  1155.  
  1156. static OSStatus SBP2DoPowerTest(
  1157.     SBPPowerTestParamsPtr        pSBPPowerTestParams)
  1158. {
  1159.     FWCommandObjectID            powerID;
  1160.     UInt32                        minVolts, reqWatts, allocWatts, flags;
  1161.     FWClientPowerNotifyProcPtr    fwClientPowerNotifyProc;
  1162.     OSStatus                    powerStatus;
  1163.     OSStatus                    status;
  1164.  
  1165.     gpFWSBP2DriverData->notificationEvent = 0;
  1166.     gpFWSBP2DriverData->notificationCounter++;
  1167.     powerID = gpFWSBP2DriverData->powerChangeID;
  1168.         
  1169.     // Imagine our device wants no less than 10 Volts (100 deciVolts)
  1170.     // and 5 Watts (50 deciWatts).
  1171.     
  1172.     if (status == noErr)
  1173.         status = FWSetPowerCommandParams (powerID, 100, 50, 0, 0);
  1174.     
  1175.     if (status == noErr)
  1176.         status = FWSetFWClientPowerNotifyProc (gpFWSBP2DriverData->fwDriverID, &DummyPowerNotify);
  1177.         
  1178.     if (status == noErr)
  1179.         powerStatus = status = FWChangePower (powerID);
  1180.             
  1181.     if (status == noErr)
  1182.         status = FWGetPowerCommandParams (powerID, &minVolts, &reqWatts, &allocWatts, &flags);
  1183.     
  1184.     // Just test that the parameters survived and that we got our 5.0 Watts
  1185.     if (status == noErr)
  1186.     {
  1187.         if (minVolts != 100) status = notFoundErr;
  1188.         if (reqWatts != 50) status = notFoundErr;
  1189.         if (allocWatts != 50) status = notFoundErr;
  1190.         if (flags != 0) status = notFoundErr;
  1191.  
  1192.     }
  1193.     
  1194.     if (status == noErr)
  1195.         status = FWGetFWClientPowerNotifyProc (gpFWSBP2DriverData->fwDriverID,
  1196.                                                &fwClientPowerNotifyProc);
  1197.     
  1198.     // Make sure the notification proc is what we set it to be.
  1199.     if ((status == noErr) && (fwClientPowerNotifyProc != DummyPowerNotify))
  1200.         status = notFoundErr;
  1201.     
  1202.     // Give back the power if we got any
  1203.     if (powerStatus == noErr)
  1204.     {
  1205.         powerStatus = FWSetPowerCommandParams (powerID, 0, 0, 0, 0);
  1206.         
  1207.         if (powerStatus == noErr)
  1208.             powerStatus = FWChangePower (powerID);
  1209.     }
  1210.     
  1211.     // We don't actually want any notification.
  1212.     if (status == noErr)
  1213.         status = FWSetFWClientPowerNotifyProc (gpFWSBP2DriverData->fwDriverID,
  1214.                                                (FWClientPowerNotifyProcPtr) 0);
  1215.         
  1216.     pSBPPowerTestParams->status = status;
  1217.     
  1218.     return noErr;
  1219. }
  1220.  
  1221.  
  1222. ////////////////////////////////////////////////////////////////////////////////
  1223. //
  1224. // SBPLoginNotify
  1225. //
  1226. //   This routine is called when a login command completes.
  1227. //
  1228.  
  1229. static OSStatus SBPLoginNotify(
  1230.     FWClientSBP2NotifyParamsPtr    pFWClientSBP2NotifyParams,
  1231.     UInt32                        *pCommandAcceptance)
  1232. {
  1233.     OSStatus                    status;
  1234.     
  1235.     if (pFWClientSBP2NotifyParams->notificationEvent == kSBP2LoginComplete)
  1236.     {
  1237.         gpFWSBP2DriverData->login = true;
  1238.         gpFWSBP2DriverData->fetchAgent.addressHi =
  1239.             *(((UInt32 *) (pFWClientSBP2NotifyParams->loginResponse)) + 1);
  1240.         gpFWSBP2DriverData->fetchAgent.addressLo =
  1241.             *(((UInt32 *) (pFWClientSBP2NotifyParams->loginResponse)) + 2);
  1242.         
  1243.         // Now that we know the fetch agent address, finish setting up the
  1244.         // command objects for writing AGENT_RESET, and DOORBELL
  1245.         
  1246.         status = FWSetAsynchCommandParams
  1247.             (gpFWSBP2DriverData->fwAGENT_RESET_ID,
  1248.              0,                                                    // generation - ignored
  1249.              gpFWSBP2DriverData->fetchAgent.addressHi,            // addr from login response
  1250.              gpFWSBP2DriverData->fetchAgent.addressLo + 4,        // + 4 to get AGENT_RESET
  1251.              (Ptr) gpFWSBP2DriverData,                            // any valid pointer will do
  1252.              4,                                                    // quadlet write
  1253.              0,                                                    // max payload - ignored
  1254.              8,                                                    // max retries
  1255.              0);                                                // no flags
  1256.  
  1257.         status = FWSetAsynchCommandParams
  1258.             (gpFWSBP2DriverData->fwDOORBELL_ID,
  1259.              0,                                                    // generation - ignored
  1260.              gpFWSBP2DriverData->fetchAgent.addressHi,            // addr from login response
  1261.              gpFWSBP2DriverData->fetchAgent.addressLo + 16,        // + 16 to get DOORBELL
  1262.              (Ptr) gpFWSBP2DriverData,                            // any valid pointer will do
  1263.              4,                                                    // quadlet write
  1264.              0,                                                    // max payload - ignored
  1265.              8,                                                    // max retries
  1266.              0);                                                // no flags
  1267.     }
  1268.     
  1269.     if (pFWClientSBP2NotifyParams->notificationEvent == kSBP2Reconnecting)
  1270.     {
  1271.         gpFWSBP2DriverData->reconnecting = true;
  1272.     }
  1273.     
  1274.     if (pFWClientSBP2NotifyParams->notificationEvent == kSBP2ReconnectComplete)
  1275.     {
  1276.         gpFWSBP2DriverData->reconnecting = false;
  1277.     }
  1278.     
  1279.     if (pFWClientSBP2NotifyParams->notificationEvent == kSBP2ReconnectFailed)
  1280.     {
  1281.         gpFWSBP2DriverData->reconnecting = false;
  1282.         gpFWSBP2DriverData->reconnectFailed = true;
  1283.     }
  1284.     
  1285.     *pCommandAcceptance = kFWClientCommandAcceptNoMore;
  1286.     return FWClientCommandIsComplete (pFWClientSBP2NotifyParams->fwClientInterfaceParams.fwClientCommandID, 0);
  1287. }
  1288.  
  1289.  
  1290. ////////////////////////////////////////////////////////////////////////////////
  1291. //
  1292. // SBPStatusNotify
  1293. //
  1294. //   This routine is called when an ORB generates status.
  1295. //
  1296.  
  1297. static OSStatus SBPStatusNotify(
  1298.     FWClientSBP2NotifyParamsPtr    pFWClientSBP2NotifyParams,
  1299.     UInt32                        *pCommandAcceptance)
  1300. {
  1301.     gpFWSBP2DriverData->notificationCounter++;
  1302.     gpFWSBP2DriverData->notificationEvent = pFWClientSBP2NotifyParams->notificationEvent;
  1303.     gpFWSBP2DriverData->notificationLength = pFWClientSBP2NotifyParams->length;
  1304.     if ((pFWClientSBP2NotifyParams->message) && (pFWClientSBP2NotifyParams->length))
  1305.         BlockCopy (pFWClientSBP2NotifyParams->message,
  1306.                    gpFWSBP2DriverData->notificationMessage,
  1307.                    pFWClientSBP2NotifyParams->length);
  1308.         
  1309.     *pCommandAcceptance = kFWClientCommandAcceptNoMore;
  1310.     return FWClientCommandIsComplete (pFWClientSBP2NotifyParams->fwClientInterfaceParams.fwClientCommandID, 0);
  1311. }
  1312.  
  1313.  
  1314. ////////////////////////////////////////////////////////////////////////////////
  1315. //
  1316. // SBPUnsolicitedStatusNotify
  1317. //
  1318. //   This routine is called when an unsolicited status is received.
  1319. //
  1320.  
  1321. static OSStatus SBPUnsolicitedStatusNotify(
  1322.     FWClientSBP2NotifyParamsPtr    pFWClientSBP2NotifyParams,
  1323.     UInt32                        *pCommandAcceptance)
  1324. {
  1325.     gpFWSBP2DriverData->notificationCounter++;
  1326.     gpFWSBP2DriverData->notificationEvent = pFWClientSBP2NotifyParams->notificationEvent;
  1327.     gpFWSBP2DriverData->notificationLength = pFWClientSBP2NotifyParams->length;
  1328.     if ((pFWClientSBP2NotifyParams->message) && (pFWClientSBP2NotifyParams->length))
  1329.         BlockCopy (pFWClientSBP2NotifyParams->message,
  1330.                    gpFWSBP2DriverData->notificationMessage,
  1331.                    pFWClientSBP2NotifyParams->length);
  1332.  
  1333.  
  1334.     // Should now reset the Unsolocited Status Enabler - or else we'll never get any more.
  1335.     // This driver just receives one to prove that it can be done.
  1336.  
  1337.     *pCommandAcceptance = kFWClientCommandAcceptNoMore;
  1338.     return FWClientCommandIsComplete (pFWClientSBP2NotifyParams->fwClientInterfaceParams.fwClientCommandID, 0);
  1339. }
  1340.  
  1341.  
  1342. #if 0
  1343. ////////////////////////////////////////////////////////////////////////////////
  1344. //
  1345. // SBP2ClientCommandCompletionProc
  1346. //
  1347. //   This routine does generic completion of FireWire client commands that
  1348. // make asynchronous FireWire service calls.
  1349. //
  1350.  
  1351. static void    SBP2ClientCommandCompletionProc(
  1352.     FWCommandObjectID            fwCommandObjectID,
  1353.     OSStatus                    commandStatus,
  1354.     UInt32                        completionProcData)
  1355. {
  1356.     FWClientCommandIsComplete ((FWClientCommandID) completionProcData,  commandStatus);
  1357. }
  1358. #endif
  1359.